package 反射;
import java.lang.reflect.Constructor;
import java.util.Arrays;

//我们通常使用new操作符创建新的实例：
//
//Person p = new Person();
//如果通过反射来创建新的实例，可以调用Class提供的newInstance()方法：
//
//Person p = Person.class.newInstance();
/*
·Java9 Class类 newInstance 过时
==============================
Class.forName("类的全限定名").newInstance();被替换为:

Class.forName("类的全限定名").getDeclaredConstructor().newInstance();

Class clazz = Person.class;
    //1.获取指定的构造器：
    //                             构造函数的一个属性类型为String，初始化使用时有几个属性就要列几个属性的类型
    //                                                     ↓
    Constructor con1 = clazz.getDeclaredConstructor(String.class);//
    //2.保证此构造器是可访问的：
    con1.setAccessible(true);//可私有属性访问
    //3.调用此构造器创建运行时类的对象（两种方法）：
    //方法一：jdk8以及8之前
   //Person p1= (Person)clazz.newInstance();
    //方法二：jdk9以及9之后：
    Person p2 =(Person)con1.newInstance("Tom");
    System.out.println(p2);

弃用原因：：
========
class.newInstance()方法传播由空构造函数引发的任何异常，包括已检查的异常。
这种方法的使用有效地绕过了编译时异常检查，否则该检查将由编译器执行。

也就是说使用class.newInstance()方法时由默认构造函数中抛出的异常，此方法检查不到

clazz.newInstance()方法由clazz.getDeclaredConstructor().newInstance()方法代替，该方法通过将构造函数抛出的任何异常包装
在（InvocationTargetException）中来避免此问题。
			try {
            Class clazz = ClassInstanceTest.class;
            clazz.getDeclaredConstructor().newInstance();
        } catch (InstantiationException e) {
            System.out.println("InstantiationException");
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            System.out.println("IllegalAccessException");
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            System.out.println("InvocationTargetException");
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            System.out.println("NoSuchMethodException");
            e.printStackTrace();
        }

*/
//调用Class.newInstance()的局限是，它只能调用该类的public无参数构造方法。如果构造方法带有参数，或者不是public，就无法直接通过Class.newInstance()来调用。
//
//为了调用任意的构造方法，Java的反射API提供了Constructor对象，它包含一个构造方法的所有信息，可以创建一个实例。Constructor对象和Method非常类似，
//不同之处仅在于它是一个构造方法，并且，调用结果总是返回实例：

//import java.lang.reflect.Constructor;
/*public class 调用构造方法 {
    public static void main(String[] args) throws Exception {
        // 获取构造方法Integer(int):
        Constructor cons1 = Integer.class.getConstructor(int.class);
        // 调用构造方法:
        Integer n1 = (Integer) cons1.newInstance(123);
        System.out.println(n1);

        // 获取构造方法Integer(String)
        Constructor cons2 = Integer.class.getConstructor(String.class);
        Integer n2 = (Integer) cons2.newInstance("456");
        System.out.println(n2);
    }
}*/





/*public class 调用构造方法 {
    public static void main(String[] args) throws Exception {
        // 获取构造方法Integer(int):
//        Constructor[] cons1 = Integer.class.getConstructors();
        Constructor[] cons1 = Integer.class.getDeclaredConstructors();
        // 调用构造方法:
//        Integer n1 = (Integer) cons1.newInstance(123);
        System.out.println(Arrays.toString(cons1));//列出
        //输出：[public java.lang.Integer(java.lang.String) throws java.lang.NumberFormatException, public java.lang.Integer(int)]
        		
//
//        // 获取构造方法Integer(String)
//        Constructor cons2 = Integer.class.getConstructor(String.class);
//        Integer n2 = (Integer) cons2.newInstance("456");
//        System.out.println(n2);
    }
}*/

public class 调用构造方法 {
    public static void main(String[] args) throws Exception {
//        Constructor cons = String.class.getConstructor(byte[]);//获取某个public的Constructor;
        Constructor[] cons = String.class.getConstructors();//获取所有public的Constructor；
//        Constructor[] cons1 = String.class.getDeclaredConstructors();//获取所有Constructor
        for (Constructor con:cons) {
        	System.out.println(con);//列出所有public的构造方法:
//        	public java.lang.String(byte[])
//        	public java.lang.String(byte[],int,int)
//        	public java.lang.String(byte[],java.nio.charset.Charset)
//        	public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException
//        	public java.lang.String(byte[],int,int,java.nio.charset.Charset)
//        	public java.lang.String(java.lang.StringBuilder)
//        	public java.lang.String(java.lang.StringBuffer)
//        	public java.lang.String(char[],int,int)
//        	public java.lang.String(char[])
//        	public java.lang.String(java.lang.String)
//        	public java.lang.String()
//        	public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException
//        	public java.lang.String(byte[],int)
//        	public java.lang.String(byte[],int,int,int)
//        	public java.lang.String(int[],int,int)
        }       
        		
        byte[] b1= {'a','b','c','d'};//{0b00000011,0b00000010};
        char[] c1= {'A','B','C','D'};
        //调用构造方法String(byte[])返回实例：
        Constructor<String> cons1 = String.class.getConstructor(byte[].class);
        String s1 = (String) cons1.newInstance(b1);
        System.out.println(s1);

        //调用构造方法String(byte[],int,int)返回实例：(相当于对字节数组subString(s,n1,n2)
        Constructor<String> cons2 = String.class.getConstructor(byte[].class,int.class,int.class);
        String s2 = (String) cons2.newInstance(b1,0,3);
        System.out.println(s2);
        
        //调用构造方法String(char[],int,int)返回实例：(相当于对字节数组subString(c,n1,n2)
        Constructor<String> cons3 = String.class.getConstructor(char[].class,int.class,int.class);
        String s3 = (String) cons3.newInstance(c1,0,3);
        System.out.println(s3);        
    }
}




//通过Class实例获取Constructor的方法如下：
//
//getConstructor(Class...)：获取某个public的Constructor；
//getDeclaredConstructor(Class...)：获取某个Constructor；
//getConstructors()：获取所有public的Constructor；
//getDeclaredConstructors()：获取所有Constructor。
//注意Constructor总是当前类定义的构造方法，和父类无关，因此不存在多态的问题。
//
//调用非public的Constructor时，必须首先通过setAccessible(true)设置允许访问。setAccessible(true)可能会失败。
//
//小结
//Constructor对象封装了构造方法的所有信息；
//
//通过Class实例的方法可以获取Constructor实例：getConstructor()，getConstructors()，getDeclaredConstructor()，getDeclaredConstructors()；
//
//通过Constructor实例可以创建一个实例对象：newInstance(Object... parameters)； 通过设置setAccessible(true)来访问非public构造方法。


